package com.zxjbyte.yiyi.framework.common.util;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.zxjbyte.yiyi.framework.common.constant.Constant;
import com.zxjbyte.yiyi.framework.common.constant.StringPool;
import com.zxjbyte.yiyi.framework.common.domain.mail.MailAttachmentMetadata;
import com.zxjbyte.yiyi.framework.common.domain.mail.MailMetadata;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;

import javax.mail.internet.MimeMessage;
import javax.mail.util.ByteArrayDataSource;
import java.io.ByteArrayInputStream;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 基于spring-boot-starter-mail的封装
 *
 * yaml相关配置请参考
 *
 * https://docs.spring.io/spring-boot/docs/2.7.8/reference/htmlsingle/
 * @Author zhangxingjia
 * @Date 2023/5/24 23:34
 * @Version: 1.0
 */
@Slf4j
@UtilityClass
public class EmailUtil {

    private static class MailSenderHolder {
        private static final JavaMailSender INSTANCE =
            SpringUtil.getBean(JavaMailSender.class);
    }

    private static JavaMailSender getMailSender() {
        return MailSenderHolder.INSTANCE;
    }

    /**
     * 发送简单邮件
     *
     * @param from 发件人
     * @param to 收件人
     * @param subject 主题
     * @param text 内容
     */
    public void sendSimpleEmail(String from, String[] to, String subject, String text) {
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        simpleMailMessage.setFrom(from);
        simpleMailMessage.setTo(to);
        simpleMailMessage.setSubject(subject);
        simpleMailMessage.setText(text);
        simpleMailMessage.setSentDate(new Date());
        getMailSender().send(simpleMailMessage);
        log.info("[{} -> {}] Send simple email success.", from, ArrayUtil.join(to, StringPool.COMMA));
    }

    /**
     * 发送简单邮件
     *
     * @param from 发件人
     * @param to 收件人
     * @param subject 主题
     * @param text 内容
     */
    public void sendSimpleEmail(String from, String to, String subject, String text) {
        EmailUtil.sendSimpleEmail(from, new String[]{to}, subject, text);
    }


    /**
     * 发送邮件
     *
     * @param metadata 邮件元数据
     */
    public void sendEmail(MailMetadata metadata) {
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        simpleMailMessage.setFrom(metadata.getFrom());
        simpleMailMessage.setTo(metadata.getTo());
        if(Objects.nonNull(metadata.getCc())){
            simpleMailMessage.setCc(metadata.getCc());
        }
        if(Objects.nonNull(metadata.getBcc())){
            simpleMailMessage.setBcc(metadata.getBcc());
        }
        simpleMailMessage.setSubject(metadata.getSubject());
        simpleMailMessage.setText(metadata.getText());
        simpleMailMessage.setSentDate(new Date());
        getMailSender().send(simpleMailMessage);
        log.info("[{} -> {}] Send email success.", metadata.getFrom(), ArrayUtil.join(metadata.getTo(), StringPool.COMMA));
    }

    /**
     * 发送HTML格式内容邮件
     * @param metadata
     */
    @SneakyThrows
    public void sendHtmlEmail(MailMetadata metadata){
        MimeMessage mimeMessage = getMailSender().createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, Constant.UTF_8);
        helper.setFrom(metadata.getFrom());
        helper.setTo(metadata.getTo());
        if(Objects.nonNull(metadata.getCc())){
            helper.setCc(metadata.getCc());
        }
        if(Objects.nonNull(metadata.getBcc())){
            helper.setBcc(metadata.getBcc());
        }
        helper.setSubject(metadata.getSubject());
        helper.setText(metadata.getText(), true);
        helper.setSentDate(new Date());
        getMailSender().send(mimeMessage);
        log.info("[{} -> {}] Send Html Email success.", metadata.getFrom(), ArrayUtil.join(metadata.getTo(), StringPool.COMMA));
    }


    /**
     * 发送带有附件的邮件
     *
     * @param metadata 邮件附件元数据
     */
    @SneakyThrows
    public void sendEmailWithAttachment(MailAttachmentMetadata metadata){
        MimeMessage mimeMessage = getMailSender().createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
        helper.setFrom(metadata.getFrom());
        helper.setTo(metadata.getTo());
        if(Objects.nonNull(metadata.getCc())){
            helper.setCc(metadata.getCc());
        }
        if(Objects.nonNull(metadata.getBcc())){
            helper.setBcc(metadata.getBcc());
        }
        helper.setSubject(metadata.getSubject());
        helper.setText(metadata.getText(), metadata.isHtml());
        helper.setSentDate(new Date());
        List<MailAttachmentMetadata.Attachment> attachmentList = metadata.getAttachmentList();
        if(CollXUtil.isNotEmpty(attachmentList)){
            for(MailAttachmentMetadata.Attachment attachment : attachmentList){
                if(ObjectUtil.isNotNull(attachment.getFile())){
                    helper.addAttachment(attachment.getAttachmentFilename(), attachment.getFile());
                } else if(ObjectUtil.isNotNull(attachment.getInputStream())){
                    String contentType = getContentType(helper, attachment.getAttachmentFilename());
                    ByteArrayDataSource byteArrayDataSource = new ByteArrayDataSource(attachment.getInputStream(), contentType);
                    helper.addAttachment(attachment.getAttachmentFilename(), byteArrayDataSource);
                } else if(ObjectUtil.isNotNull(attachment.getContentBytes())){
                    ByteArrayInputStream byteArrayInputStream = IoUtil.toStream(attachment.getContentBytes());
                    String contentType = getContentType(helper, attachment.getAttachmentFilename());
                    ByteArrayDataSource byteArrayDataSource = new ByteArrayDataSource(byteArrayInputStream, contentType);
                    helper.addAttachment(attachment.getAttachmentFilename(), byteArrayDataSource);
                } else if(ObjectUtil.isNotNull(attachment.getDataSource())){
                    helper.addAttachment(attachment.getAttachmentFilename(), attachment.getDataSource());
                }
            }
        }
        getMailSender().send(mimeMessage);
        log.info("[{} -> {}] Send attachment email success.", metadata.getFrom(), ArrayUtil.join(metadata.getTo(), StringPool.COMMA));
    }

    private String getContentType(MimeMessageHelper helper, String attachmentFilename){
        String contentType = helper.getFileTypeMap().getContentType(attachmentFilename);
        if(StrUtil.isBlank(contentType)){
            contentType = "application/octet-stream";
        }
        return contentType;
    }
}
